#include "sdl_debug.h"
#include "boost/date_time/posix_time/posix_time.hpp"


namespace sdl_debug {

/*
 * class chan
 */

chan::chan(const std::string & n = "", const int & l = 0, const debug_method & m = ounspecified) : name(n), lowpass(0), out_method(m), output(NULL)
{
}

bool chan::operator==(const chan & s)
{
    return name == s.name;
}

/*
 * class debug
 */
debug::debug() : sdl_prim("DEBUG")
{
    using namespace boost::posix_time;
    output_f.open(sdl_default_debug_file, std::ios_base::app);

    ptime now = second_clock::local_time();
#ifdef WIN32
    global_output = &output_f;
    out_method = ofile;
#else
    global_output = &std::cout;
    out_method = ostdout;
#endif
    (*global_output) << std::endl << "==== Debug output started " << now << " ====" << std::endl;
    suppress = false;
    lowpass = 0;
}

debug::~debug()
{
    output_f.close();
    channels.clear();
}

void debug::message(const std::string & ch, int level, const std::string & message, const std::string & file, const int & loc)
{
    chan & c = get_channel(ch);

    if (level >= lowpass)
        if (level >= c.lowpass) {
            std::stringstream mesg;
            mesg << c.name << "(" << level << "): <" << file << "," << loc << ">: ";

            if (c.output != NULL) {
                (*c.output) << mesg.str();
                (*c.output) << message << std::endl;
            } else switch (c.out_method) {

                case ounspecified:
                    switch (out_method) {
                    case ostdout:
                        (*global_output) << mesg.str();
                        (*global_output) << message << std::endl;
                        break;
                    case ofile:
                        (*((std::ofstream*)(global_output))) << mesg.str();
                        (*((std::ofstream*)(global_output))) << message << std::endl;
                        break;
                    case osstream:
                        (*((std::stringstream*)(global_output))) << mesg.str();
                        (*((std::stringstream*)(global_output))) << message << std::endl;
                        break;
                    default:
                        (*global_output) << mesg.str();
                        (*global_output) << message << std::endl;
                        break;
                    }
                    break;

                case ostdout:
                    std::cout << mesg.str();
                    std::cout << message << std::endl;
                    break;

                case ofile:
                    output_f << mesg.str();
                    output_f << message << std::endl;
                    break;

                case ocustom:
                    (*output_c) << mesg.str();
                    (*output_c) << message << std::endl;
                    break;

                case osstream:
                    output_ss << mesg.str();
                    output_ss << message << std::endl;
                    break;
                }
        }
}

///to samo co message, ale wywala wyjątek

void debug::error(const std::string & ch, int level, const std::string & mess, const std::string & file, const int & loc)
{
    std::stringstream e_msg;
    e_msg << ch << ":<" << file << "," << loc << ">: " << mess << std::endl;
#ifdef WIN32
    message(ch, level, mess, file, loc);
#endif
    throw (sdlex::exception(e_msg.str()));
}

/*
 * ustawienia zewnętrzne
 */
void debug::set_custom_output(std::ostream * o)
{
    output_c = o;
    global_output = output_c;
    out_method = ocustom;
}

void debug::set_custom_output(const std::string & ch, std::ostream * o)
{
    get_channel(ch).output = o;
}

void debug::set_output_method(debug_method m)
{
    out_method = m;

    switch (m) {

    case ostdout:
        global_output = &std::cout;
        break;

    case ofile:
        global_output = &output_f;
        break;

    case ocustom:
        global_output = output_c;
        break;

    case osstream:
        global_output = &output_ss;
        break;

    case ounspecified:
        break;

    }
}

void debug::set_output_method(const std::string & ch, const debug_method & method)
{
    get_channel(ch).out_method = method;
}

void debug::set_lowpass(int l)
{
    lowpass = l;
}

void debug::set_lowpass(const std::string & ch, int l)
{
    get_channel(ch).lowpass = l;
}

void debug::disable_messages()
{
    suppress = true;
}

void debug::enable_messages()
{
    suppress = false;
}

bool debug::disabled()
{
    return suppress;
}

/*
 * różne wyjmowanie
 */

/**
 * wyjmuje albo tworzy kanał
 */
chan & debug::get_channel(const std::string & s)
{
    chan * ret = NULL;
    std::list<chan>::iterator c = std::find(channels.begin(), channels.end(), chan(s));

    if (c == channels.end()) {
        channels.push_back(chan(s));
        ret = &channels.back();
    } else {
        ret = &(*c);
    }

    if (ret != NULL)
        return *ret;
}

std::ostream * debug::get_output()
{
    return global_output;
}

std::stringstream * debug::get_output_ss()
{
    return &output_ss;
}

std::ofstream * debug::get_output_f()
{
    return &output_f;
}


};

template<> sdl_ptr<sdl_debug::debug> sdl_singleton<sdl_debug::debug>::__field = NULL;
